/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ants;

import java.awt.Point;
import java.io.*;
import java.net.Socket;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.concurrent.Semaphore;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;

/**
 *
 * @author
 */
public class ServerDispatcher implements Runnable {

    int numCli;
    int mov;
    Socket output;
    Semaphore sem;
    socketshormigas serverdata;
    Player jugador;
    int actual;
    Point hormiguero;
    ServerDispatcher(int n, Semaphore s, Socket o, socketshormigas d) {
        output = o;
        serverdata = d;
        numCli = n;
        sem = s;
        mov = 0;
        hormiguero = d.mapa.getHormiguero(numCli + 1);
        jugador = new Player(numCli, hormiguero);
        
        agregar_ants2map(jugador.Player_ants_warriors, hormiguero);
        agregar_ants2map(jugador.Player_ants_explorers, hormiguero);
        agregar_ants2map(jugador.Player_ants_workers, hormiguero);

        d.Player_list.add(jugador);
        actual = 0;

    }

    void agregar_ants2map(LinkedList hormigas, Point place) {
        for (int i = 0; i < hormigas.size(); i++) {
            Ant nueva = (Ant) hormigas.get(i);
            serverdata.mapa.cells[place.x][place.y].addAnt(nueva);

            /*
             * int idExploradora = jugador.Player_ants_workers.get(i).id; int
             * idRecolectora = jugador.Player_ants_explorers.get(i).id;
             */
        }

    }

    @Override
    public void run() {
        //condicion para esperar a que se conecten todos los clientes
        //comentada por propositos de testing
        while (serverdata.numCli != serverdata.maxCli) {
            System.out.print("");
        }
        try {
            System.out.println("Sirvo al cliente " + numCli);
            OutputStream aux = output.getOutputStream();
            ObjectOutputStream os = new ObjectOutputStream(aux);
            InputStream aux2 = output.getInputStream();
            ObjectInputStream is = new ObjectInputStream(aux2);
            // DataOutputStream enteros = new DataOutputStream(aux);//enviar enteros
            //os.writeObject("Esperando a otros clientes para empezar partida");
            // enteros.writeInt(numCli);//enviar enteros
            //os.writeObject("Esperando a otros clientes para empezar partida");
            //os.writeObject(testing());
            //enviariddeturno
            
            JFrame aplicacion = new JFrame("Jugador " + numCli);
            Panel panel = new Panel(jugador, serverdata.mapa);
            aplicacion.add(panel);
            aplicacion.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            aplicacion.setSize(((int) (680 / (serverdata.mapa.h + 2))) * (serverdata.mapa.w + 2), 700);
            aplicacion.setVisible(true);
            os.writeObject(new Inicial(serverdata.mapa.h + 2, serverdata.mapa.w + 2, Constantes.max_workers, Constantes.max_explorers, Constantes.max_warriors, numCli, hormiguero));
            System.out.println("Mande el estado inicial");

            //ciclo while food!=0 and obreras!=0
            int[][] playerNumbers = new int[serverdata.maxCli][3];
            playerNumbers = TypeRaffle.randy(serverdata.maxCli);
            //Knowledge know=new Knowledge(jugador,serverdata.mapa,TypeRaffle.randy(serverdata.maxCli));
            
            while (serverdata.remfood != 0) {//hace falta manipular esta variable y ponerle un valor al cargar el mapa y verificar los puntos de comida
                //validarturno()---semaforo!
                try {
                    sem.acquire();//semaforo que esta solo como medida de seguridad
                } catch (InterruptedException ex) {
                    Logger.getLogger(ServerDispatcher.class.getName()).log(Level.SEVERE, null, ex);
                }
                if (numCli == serverdata.turno) {
                   //quitamos el semaforo para ver que pedo
                    

                    /*
                     * switch (mov) { case 0:
                     *
                     */           
                    //Se enlistan todas las hormigas del jugador actual en una sola lista y se mandan junto al FinalView
                    HashMap ListaConocimiento = new HashMap();
                    Conocimiento conocidos[];
                    for(int i=1; i<jugador.Player_ants.length; i++){
                        Ant hormiga = (Ant) jugador.Player_ants[i];
                        int[] hormigas = Antview(serverdata.mapa.cells[hormiga.place.x][hormiga.place.y].ants, playerNumbers);
                        conocidos = Knowing.known(playerNumbers, hormigas, serverdata.maxCli);
                        ListaConocimiento.put(hormiga.id, conocidos);
                    }
                    FinalView finalView = new FinalView(new AntsView(jugador, serverdata.mapa, actual), new Knowledge(jugador, serverdata.mapa, playerNumbers),ListaConocimiento);
                    os.writeObject(finalView);
                    os.flush();
                    //System.out.println("Mande el AntsView");
                    //se mandan las perspectivas de las hormigas
                    //las clases pertinentes deben ser agregadas
                            /*
                     * mov++; break; case 1://recive movimientos de jugador
                     *
                     */
                    MoveList movimientos;
                    movimientos = (MoveList) is.readObject();
                    ListIterator itr = movimientos.moves.listIterator();
                    
                    while (itr.hasNext()) {
                        Move movimiento = (Move) itr.next();
                        Ant hormiga = (Ant) jugador.Player_ants[movimiento.id_H];
                        if (validar_movimiento(movimiento, serverdata.mapa)) {
                            serverdata.mapa.cells[hormiga.place.x][hormiga.place.y].removeAnt(hormiga);
                            hormiga.move(movimiento.move, actual);
                            serverdata.mapa.cells[hormiga.place.x][hormiga.place.y].addAnt(hormiga);
                            if (serverdata.mapa.cells[hormiga.place.x][hormiga.place.y].comida != 0) {
                                int posee = hormiga.food;
                                hormiga.take(serverdata.mapa.cells[hormiga.place.x][hormiga.place.y].comida);
                                int posee_ahora = hormiga.food;
                                int tomado = posee_ahora - posee;
                                serverdata.mapa.cells[hormiga.place.x][hormiga.place.y].removeFood(tomado);
                            }
                            if (hormiga.place.equals(jugador.hormiguero)) {
                                if (hormiga.comida_cargada() > 0) {
                                    int cuanto = hormiga.comida_cargada();
                                    hormiga.score();
                                    //Aquí se debería de depositar puntos al usuario??
                                    serverdata.mapa.food = serverdata.mapa.getTotalFood() - cuanto;
                                    serverdata.puntaje[numCli] += cuanto;
                                }

                            }
                        }
                        /*                        
                        for (int i = 0; i < 9; i++) {
                            System.out.print(hormigas[i]);
                        }
                        */
                    }
                    HashMap ListaConocimiento2 = new HashMap();
                    Conocimiento conocidos2[];
                    for(int i=1; i<jugador.Player_ants.length; i++){
                        Ant hormiga2 = (Ant) jugador.Player_ants[i];
                        int[] hormigas2 = Antview(serverdata.mapa.cells[hormiga2.place.x][hormiga2.place.y].ants, playerNumbers);
                        conocidos2 = Knowing.known(playerNumbers, hormigas2, serverdata.maxCli);
                        ListaConocimiento2.put(hormiga2.id, conocidos2);
                    }
                    os.writeObject(ListaConocimiento2);
                    os.flush();
                    //Batallav2 ba = new Batallav2();
                    //System.out.println("Antes de guerra");
                    //ba.pelear(serverdata.mapa, numCli); //aqui invocamos la batalla, necesita el mapa y el numero del cliente en turno
                    //System.out.println("Guerraaaaaa!!!!!!");
                    panel.repaint();
                    actual++;
                    //System.out.println(actual);
                    //rellenar aqui los movimientos necesarios para recibir
                    //el objeto del cliente
                    //aun no se agregan las estructuras para el manejo
                    //de los datos en esta clase
                                /*
                     * if(numCli == (serverdata.maxCli-1))//el ultimo cliente en
                     * ser atendido le pide al server que resuelva movimientos
                     * serverdata.resolver();//se actualiza comida, batallas,
                     * etc. No implementada aun //pueden pasarle como argumento
                     * lo que te da el cliente
                     */
                    /*
                     * mov = 0; break; }
                     *
                     */
                    serverdata.turno = (serverdata.turno + 1) % serverdata.maxCli; //cambiamos de turno
                    System.out.print(serverdata.puntaje[numCli]+" ");
                    if(serverdata.turno == 0)
                        System.out.println();
                    
                    //
                }
                //quitamos el semaforo para ver que pedo
                sem.release();//semaforo solo por cuestiones de seguridad
                //System.out.print("");
            }

            /*
             * while(serverdata.remfood != 0){//hace falta manipular esta
             * variable y ponerle un valor al cargar el mapa y verificar los
             * puntos de comida //validarturno()---semaforo! if(numCli ==
             * serverdata.turno){ sem.acquire();//semaforo que esta solo como
             * medida de seguridad switch(mov){ case 0: //se mandan las
             * perspectivas de las hormigas //las clases pertinentes deben ser
             * agregadas mov++; break; case 1://recive movimientos de jugador
             * os.writeObject("Preparado para recibir datos"); //rellenar aqui
             * los movimientos necesarios para recibir //el objeto del cliente
             * //aun no se agregan las estructuras para el manejo //de los datos
             * en esta clase if(numCli == (serverdata.maxCli-1))//el ultimo
             * cliente en ser atendido le pide al server que resuelva
             * movimientos serverdata.resolver();//se actualiza comida,
             * batallas, etc. No implementada aun //pueden pasarle como
             * argumento lo que te da el cliente
             *
             * mov = 0; break; } serverdata.turno =
             * (serverdata.turno+1)%serverdata.maxCli; //cambiamos de turno
             * sem.release();//semaforo solo por cuestiones de seguridad } }
             */

            output.close();
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(ServerDispatcher.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }/*
         * catch(InterruptedException e){ System.out.println(e.getMessage());
         * }/*catch(ClassNotFoundException e){
         * System.out.println(e.getMessage()); }
         */ //catch en caso de que se necesite en un futuro
    }

    /*
     * public AntsView testing() { AntsView lala = new AntsView(); Perspective
     * burro = new Perspective(); Celda link = new Celda(); Tile lolo = new
     * Tile(link); burro.addTile(lolo); lala.addPerspective(burro); return lala;
     * }
     */
    private boolean validar_movimiento(Move movimiento, Mapa mapa) {

        if (!(validar_velocidad(actual, jugador.Player_ants[movimiento.id_H]))) {
            return false;
        }
        Ant dummy = new Ant(jugador.Player_ants[movimiento.id_H].id,
                jugador.Player_ants[movimiento.id_H].type,
                jugador.Player_ants[movimiento.id_H].place.x,
                jugador.Player_ants[movimiento.id_H].place.y);
        dummy.move(movimiento.move, -1);
        if (serverdata.mapa.cells[dummy.place.x][dummy.place.y].tipo == Constantes.obstaculo) {
            return false;
        }
        return true;

    }

    private boolean validar_velocidad(int actual, Ant hormiga) {

        if (hormiga.last == -1) {
            return true;
        }
        switch (hormiga.type) {
            case Constantes.explorer_id:
                if (actual - hormiga.last >= Constantes.vel_explorers) {
                    return true;
                }
            case Constantes.worker_id:
                if (actual - hormiga.last >= Constantes.vel_workers) {
                    return true;
                }
            case Constantes.warrior_id:
                if (actual - hormiga.last >= Constantes.vel_warriors) {
                    return true;
                }
        }
        return false;
    }

    public int[] Antview(LinkedList hormigas, int[][] random) {
        int[] AntType;
        int[][] val = new int[serverdata.maxCli][3];
        for (int i = 0; i < hormigas.size(); i++) {
            val[((Ant) hormigas.get(i)).jugador][((Ant) hormigas.get(i)).type]++;
        }
        AntType = new int[(serverdata.maxCli) * 3];
        for (int i = 0; i < serverdata.maxCli; i++) {
            for (int j = 0; j < 3; j++) {
                AntType[random[i][j]] = val[i][j];
            }
        }
        return AntType;
    }
}
